Dynamic Rankings
Time Limit: 10 Sec Memory Limit: 128 MB
Description
给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。
第一行有两个正整数
分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n]。
接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。
Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。
C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。
Output
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
HINT
m,n≤10000 , 0≤ai≤1e9。
Main idea
询问区间中第k小的数是多少,需要支持单点修改点的权值。
Solution
我们看到这道题,发现对于一个询问应该是可以二分查找答案的,那么我们从整体二分的角度来思考。
我们发现,如果没有修改的话,显然很简单,直接整体二分将所有询问一起操作 即可。
但是我们有操作,那应该怎么办呢?
我们对于每一次修改,记录一下原来的值,简单来说,就是对于每一次操作,记录一下若opt=1 ,则表示这个点在这个状态的值 ;若opt=3 ,则表示这是一个询问 ,
我们对于修改 来说,新增一个opt=2 ,表示在修改之前的值 。也就是说,我们在执行一个区间的操作时,如果发现一个opt=2,那么之前一定有一个一样的值的opt为1,并且其已经对答案造成影响,现在那个元素已经被修改了,就要相应地减去它之前对答案的影响,这样就完成了修改。
然后我们整体二分权值,像静态查询kth 那样修改一下即可。思路一气呵成 (≧▽≦)/
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 #include <bits/stdc++.h> using namespace std;const int ONE=30005 ;const int INF=1e9 +1 ;int n,m;int x,y,k;char ch[3 ];int cnt,Num;int a[ONE],record[ONE];int Ans[ONE];struct power { int opt,cnt; int l,r,k; int pos,value; int cur; }oper[ONE],qL[ONE],qR[ONE]; int get () { int res=1 ,Q=1 ;char c; while ( (c=getchar ())<48 || c>57 ) if (c=='-' )Q=-1 ; res=c-48 ; while ( (c=getchar ())>=48 && c<=57 ) res=res*10 +c-48 ; return res*Q; } namespace Bit{ struct power { int value; }Node[ONE]; int lowbit (int i) { return i&-i; } void Update (int R,int x) { for (int i=R;i<=n;i+=lowbit (i)) Node[i].value+=x; } int Query (int R) { int res=0 ; for (int i=R;i>=1 ;i-=lowbit (i)) res+=Node[i].value; return res; } } void Solve (int l,int r,int L,int R) { if (l>r) return ; if (L==R) { for (int i=l;i<=r;i++) if (oper[i].opt==3 ) Ans[oper[i].cnt] = L; return ; } int M=(L+R)>>1 ; for (int i=l;i<=r;i++) { if (oper[i].opt==1 && oper[i].value<=M) Bit::Update (oper[i].pos,1 ); if (oper[i].opt==2 && oper[i].value<=M) Bit::Update (oper[i].pos,-1 ); if (oper[i].opt==3 ) record[i]=Bit::Query (oper[i].r) - Bit::Query (oper[i].l-1 ); } for (int i=l;i<=r;i++) { if (oper[i].opt==1 && oper[i].value<=M) Bit::Update (oper[i].pos,-1 ); if (oper[i].opt==2 && oper[i].value<=M) Bit::Update (oper[i].pos,1 ); } int l_num=0 ,r_num=0 ; for (int i=l;i<=r;i++) { if (oper[i].opt!=3 ) { if (oper[i].value <= M) qL[++l_num]=oper[i]; else qR[++r_num]=oper[i]; } else { if (oper[i].cur + record[i] >= oper[i].k) qL[++l_num]=oper[i]; else { qR[++r_num]=oper[i]; qR[r_num].cur+=record[i]; } } } int t=l; for (int i=1 ;i<=l_num;i++) oper[t++]=qL[i]; for (int i=1 ;i<=r_num;i++) oper[t++]=qR[i]; Solve (l,l+l_num-1 ,L,M); Solve (l+l_num,r,M+1 ,R); } int main () { n=get (); m=get (); for (int i=1 ;i<=n;i++) { a[i]=get (); oper[++cnt].opt=1 ; oper[cnt].pos=i; oper[cnt].value=a[i]; } for (int i=1 ;i<=m;i++) { scanf ("%s" ,ch); if (ch[0 ]=='Q' ) { x=get (); y=get (); k=get (); oper[++cnt].opt=3 ; oper[cnt].l=x; oper[cnt].r=y; oper[cnt].k=k; oper[cnt].cnt=++Num; } else { x=get (); y=get (); oper[++cnt].opt=2 ; oper[cnt].pos=x; oper[cnt].value=a[x]; oper[++cnt].opt=1 ; oper[cnt].pos=x; oper[cnt].value=y; a[x]=y; } } Solve (1 ,cnt,0 ,INF); for (int i=1 ;i<=Num;i++) printf ("%d\n" ,Ans[i]); }